import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { v4 as uuidv4 } from 'uuid';
import { CopilotRequestLog } from '../../database/entities/copilot-request-log.entity';
import { CopilotFieldMapping } from '../../database/entities/copilot-field-mapping.entity';
import { RequestPhase, RequestStatus, MappingType } from '../../database/entities/copilot-types';

export interface RequestContext {
  requestId: string;
  userId?: string;
  userIp?: string;
  userAgent?: string;
  modelName?: string;
  isStreaming?: boolean;
  hasTools?: boolean;
}

export interface PhaseData {
  headers?: Record<string, any>;
  body?: Record<string, any>;
  method?: string;
  url?: string;
  status?: number;
  timestamp: Date;
}

export interface FieldChange {
  fieldPath: string;
  fromValue?: any;
  toValue?: any;
  mappingType: MappingType;
  fromFieldName?: string;
  toFieldName?: string;
  transformationRule?: string;
  transformerName?: string;
}

@Injectable()
export class CopilotRequestLoggerService {
  private readonly logger = new Logger(CopilotRequestLoggerService.name);
  private readonly activeRequests = new Map<string, CopilotRequestLog>();

  constructor(
    @InjectRepository(CopilotRequestLog)
    private readonly requestLogRepository: Repository<CopilotRequestLog>,
    @InjectRepository(CopilotFieldMapping)
    private readonly fieldMappingRepository: Repository<CopilotFieldMapping>,
  ) {}

  /**
   * 创建新的请求日志记录
   */
  async createRequestLog(context: RequestContext): Promise<string> {
    try {
      const requestLog = new CopilotRequestLog();
      requestLog.requestId = context.requestId;
      requestLog.userId = context.userId;
      requestLog.userIp = context.userIp;
      requestLog.userAgent = context.userAgent;
      requestLog.modelName = context.modelName;
      requestLog.isStreaming = context.isStreaming || false;
      requestLog.hasTools = context.hasTools || false;
      requestLog.status = RequestStatus.IN_PROGRESS;
      requestLog.currentPhase = RequestPhase.CLIENT_REQUEST;

      const savedLog = await this.requestLogRepository.save(requestLog);
      this.activeRequests.set(context.requestId, savedLog);
      
      return context.requestId;
    } catch (error) {
      this.logger.error(`Failed to create request log: ${error.message}`);
      throw error;
    }
  }

  /**
   * 记录客户端请求接收阶段
   */
  async logClientRequest(requestId: string, phaseData: PhaseData): Promise<void> {
    try {
      const requestLog = await this.getOrCreateRequestLog(requestId);
      
      requestLog.clientRequestHeaders = this.sanitizeHeaders(phaseData.headers);
      requestLog.clientRequestBody = this.sanitizeRequestBody(phaseData.body);
      requestLog.clientRequestMethod = phaseData.method;
      requestLog.clientRequestUrl = phaseData.url;
      requestLog.clientRequestTime = phaseData.timestamp;
      requestLog.currentPhase = RequestPhase.CLIENT_REQUEST;

      await this.requestLogRepository.save(requestLog);
      this.logger.debug(`Logged client request for ${requestId}`);
    } catch (error) {
      this.logger.error(`Failed to log client request for ${requestId}: ${error.message}`);
    }
  }

  /**
   * 记录转发到Copilot请求阶段
   */
  async logCopilotRequest(requestId: string, phaseData: PhaseData): Promise<void> {
    try {
      const requestLog = await this.getOrCreateRequestLog(requestId);
      
      requestLog.copilotRequestHeaders = this.sanitizeHeaders(phaseData.headers);
      requestLog.copilotRequestBody = phaseData.body;
      requestLog.copilotRequestMethod = phaseData.method;
      requestLog.copilotRequestUrl = phaseData.url;
      requestLog.copilotRequestTime = phaseData.timestamp;
      requestLog.currentPhase = RequestPhase.COPILOT_REQUEST;

      // 计算转换耗时
      if (requestLog.clientRequestTime) {
        requestLog.conversionDuration = phaseData.timestamp.getTime() - requestLog.clientRequestTime.getTime();
      }

      await this.requestLogRepository.save(requestLog);
      this.logger.debug(`Logged copilot request for ${requestId}`);
    } catch (error) {
      this.logger.error(`Failed to log copilot request for ${requestId}: ${error.message}`);
    }
  }

  /**
   * 记录Copilot响应阶段
   */
  async logCopilotResponse(requestId: string, phaseData: PhaseData): Promise<void> {
    try {
      const requestLog = await this.getOrCreateRequestLog(requestId);
      
      requestLog.copilotResponseHeaders = this.sanitizeHeaders(phaseData.headers);
      requestLog.copilotResponseBody = phaseData.body;
      requestLog.copilotResponseStatus = phaseData.status;
      requestLog.copilotResponseTime = phaseData.timestamp;
      requestLog.currentPhase = RequestPhase.COPILOT_RESPONSE;

      // 计算API调用耗时
      if (requestLog.copilotRequestTime) {
        requestLog.copilotApiDuration = phaseData.timestamp.getTime() - requestLog.copilotRequestTime.getTime();
      }

      // 提取token使用情况
      if (phaseData.body?.usage) {
        requestLog.actualInputTokens = phaseData.body.usage.prompt_tokens;
        requestLog.actualOutputTokens = phaseData.body.usage.completion_tokens;
      }

      await this.requestLogRepository.save(requestLog);
      this.logger.debug(`Logged copilot response for ${requestId}`);
    } catch (error) {
      this.logger.error(`Failed to log copilot response for ${requestId}: ${error.message}`);
    }
  }

  /**
   * 记录客户端响应阶段（完成）
   */
  async logClientResponse(requestId: string, phaseData: PhaseData): Promise<void> {
    try {
      const requestLog = await this.getOrCreateRequestLog(requestId);
      
      requestLog.clientResponseHeaders = this.sanitizeHeaders(phaseData.headers);
      requestLog.clientResponseBody = this.sanitizeResponseBody(phaseData.body);
      requestLog.clientResponseStatus = phaseData.status;
      requestLog.clientResponseTime = phaseData.timestamp;
      requestLog.currentPhase = RequestPhase.CLIENT_RESPONSE;
      requestLog.status = RequestStatus.SUCCESS;

      // 计算总耗时
      if (requestLog.clientRequestTime) {
        requestLog.totalDuration = phaseData.timestamp.getTime() - requestLog.clientRequestTime.getTime();
      }

      await this.requestLogRepository.save(requestLog);
      this.activeRequests.delete(requestId);
      this.logger.debug(`Logged client response for ${requestId}`);
    } catch (error) {
      this.logger.error(`Failed to log client response for ${requestId}: ${error.message}`);
    }
  }

  /**
   * 记录错误信息
   */
  async logError(requestId: string, error: Error, phase?: RequestPhase, data?: any): Promise<void> {
    try {
      const requestLog = await this.getOrCreateRequestLog(requestId);
      
      requestLog.status = RequestStatus.ERROR;
      requestLog.errorMessage = error.message;
      requestLog.errorStack = error.stack;
      requestLog.errorPhase = phase || requestLog.currentPhase;

      if (data) {
        requestLog.debugInfo = data;
      }

      await this.requestLogRepository.save(requestLog);
      this.activeRequests.delete(requestId);
      
      this.logger.error(`Error logged for request ${requestId}: ${error.message}`);
    } catch (logError) {
      this.logger.error(`Failed to log error for ${requestId}: ${logError.message}`);
    }
  }

  /**
   * 记录Token刷新相关操作（向后兼容）
   */
  async logTokenRefresh(requestId: string, service: string, message: string, data?: any, duration?: number): Promise<void> {
    try {
      // 对于Token刷新，我们记录为一个特殊的日志条目
      this.logger.log(`Token Refresh - ${service}: ${message}`, {
        requestId,
        service,
        data: this.sanitizeTokenData(data),
        duration
      });
    } catch (error) {
      this.logger.error(`Failed to log token refresh: ${error.message}`);
    }
  }

  /**
   * 兼容旧版本的logError方法（5个参数）
   */
  async logErrorLegacy(
    requestId: string, 
    service: string, 
    message: string, 
    error: Error, 
    data?: any
  ): Promise<void> {
    try {
      // 将旧版本调用转换为新版本
      await this.logError(requestId, error, undefined, { 
        service, 
        message, 
        ...data 
      });
    } catch (logError) {
      this.logger.error(`Failed to log legacy error: ${logError.message}`);
    }
  }

  /**
   * 清理Token数据中的敏感信息
   */
  private sanitizeTokenData(data?: any): any {
    if (!data) return data;

    const sanitized = { ...data };
    
    // 脱敏敏感字段
    if (sanitized.githubToken) {
      sanitized.githubToken = `${sanitized.githubToken.substring(0, 10)}...`;
    }
    
    if (sanitized.copilotToken) {
      sanitized.copilotToken = `${sanitized.copilotToken.substring(0, 50)}...`;
    }

    if (sanitized.responseData?.token) {
      sanitized.responseData.token = '[REDACTED]';
    }

    return sanitized;
  }

  // === 向后兼容方法 ===

  /**
   * 向后兼容：logRequestStart
   */
  async logRequestStart(requestId: string, service: string, message: string, data?: any): Promise<void> {
    this.logger.log(`${service}: ${message}`, { requestId, ...data });
  }

  /**
   * 向后兼容：logConversionComplete  
   */
  async logConversionComplete(requestId: string, service: string, fromFormat: string, toFormat: string, data?: any, duration?: number): Promise<void> {
    // 控制台日志
    this.logger.log(`${service}: Conversion completed: ${fromFormat} -> ${toFormat}`, { requestId, duration, ...data });
    
    // 数据库日志记录
    try {
      const requestLog = await this.getOrCreateRequestLog(requestId);
      if (fromFormat === 'Anthropic' && toFormat === 'Copilot') {
        // 记录转发到Copilot的请求
        await this.logCopilotRequest(requestId, {
          headers: data?.headers || {},
          body: data?.convertedRequest || {},
          method: 'POST',
          url: '/chat/completions',
          timestamp: new Date()
        });
      } else if (fromFormat === 'Copilot' && toFormat === 'Anthropic') {
        // 记录Copilot响应
        await this.logCopilotResponse(requestId, {
          headers: {},
          body: data?.copilotResponse || {},
          status: 200,
          timestamp: new Date()
        });
      }
    } catch (error) {
      this.logger.error(`Failed to log conversion to database: ${error.message}`);
    }
  }

  /**
   * 向后兼容：logResponseConversion
   */
  async logResponseConversion(requestId: string, service: string, message: string, data?: any, duration?: number): Promise<void> {
    // 控制台日志
    this.logger.log(`${service}: ${message}`, { requestId, duration, ...data });
    
    // 数据库日志记录 - 最终客户端响应
    try {
      await this.logClientResponse(requestId, {
        headers: { 'Content-Type': 'application/json' },
        body: data?.anthropicResponse || {},
        status: 200,
        timestamp: new Date()
      });
    } catch (error) {
      this.logger.error(`Failed to log response conversion to database: ${error.message}`);
    }
  }

  /**
   * 向后兼容：logRequestComplete
   */
  async logRequestComplete(requestId: string, service: string, message: string, data?: any, totalDuration?: number): Promise<void> {
    // 控制台日志
    this.logger.log(`${service}: ${message}`, { requestId, totalDuration, ...data });
    
    // 数据库日志记录 - 完成请求并设置性能指标
    try {
      const requestLog = await this.getOrCreateRequestLog(requestId);
      requestLog.status = RequestStatus.SUCCESS;
      requestLog.totalDuration = totalDuration || 0;
      
      // 设置token使用信息
      if (data?.usage) {
        requestLog.actualInputTokens = data.usage.input_tokens || 0;
        requestLog.actualOutputTokens = data.usage.output_tokens || 0;
      }
      
      await this.requestLogRepository.save(requestLog);
    } catch (error) {
      this.logger.error(`Failed to complete request log in database: ${error.message}`);
    }
  }

  /**
   * 向后兼容：logApiCallStart
   */
  async logApiCallStart(requestId: string, service: string, url: string, data?: any): Promise<void> {
    this.logger.log(`${service}: Calling API: ${url}`, { requestId, ...data });
  }

  /**
   * 向后兼容：logApiCallComplete
   */
  async logApiCallComplete(requestId: string, service: string, status: number, data?: any, duration?: number): Promise<void> {
    this.logger.log(`${service}: API call completed with status ${status}`, { requestId, duration, ...data });
  }

  /**
   * 向后兼容：logCopilotRequest (旧版本格式)
   */
  async logCopilotRequestLegacy(data: any): Promise<void> {
    this.logger.log(`Copilot request: ${data.message}`, data);
  }

  /**
   * 向后兼容：logConversionStart
   */
  async logConversionStart(requestId: string, service: string, fromFormat: string, toFormat: string, data?: any): Promise<void> {
    this.logger.log(`${service}: Converting from ${fromFormat} to ${toFormat}`, { requestId, ...data });
  }

  /**
   * 向后兼容：logCopilotRequest（旧版本格式，用于适配器中的日志调用）
   */
  async logCopilotRequestLegacyFormat(logData: {
    requestId: string;
    phase?: string;
    service?: string;
    level?: string;
    message: string;
    data?: any;
  }): Promise<void> {
    this.logger.log(`${logData.service || 'CopilotService'}: ${logData.message}`, {
      requestId: logData.requestId,
      phase: logData.phase,
      level: logData.level,
      ...logData.data
    });
  }

  /**
   * 记录字段映射变化
   */
  async logFieldMappings(
    requestId: string, 
    fromPhase: RequestPhase, 
    toPhase: RequestPhase, 
    fieldChanges: FieldChange[],
    transformerName?: string
  ): Promise<void> {
    try {
      const requestLog = await this.getOrCreateRequestLog(requestId);
      
      const mappings = fieldChanges.map(change => 
        CopilotFieldMapping.create({
          requestLogId: requestLog.id,
          fromPhase,
          toPhase,
          mappingType: change.mappingType,
          fieldPath: change.fieldPath,
          fromFieldName: change.fromFieldName,
          toFieldName: change.toFieldName,
          fromValue: change.fromValue,
          toValue: change.toValue,
          transformationRule: change.transformationRule,
          transformerName: transformerName
        })
      );

      await this.fieldMappingRepository.save(mappings);
      this.logger.debug(`Logged ${fieldChanges.length} field mappings for ${requestId}`);
    } catch (error) {
      this.logger.error(`Failed to log field mappings for ${requestId}: ${error.message}`);
    }
  }

  /**
   * 创建请求上下文 (返回requestId供整个请求链路使用)
   */
  createRequestContext(context?: Partial<RequestContext>): string {
    const requestId = uuidv4();
    
    // 如果提供了上下文信息，立即创建日志记录
    if (context) {
      this.createRequestLog({ requestId, ...context }).catch(error => {
        this.logger.error(`Failed to create request log: ${error.message}`);
      });
    }
    
    return requestId;
  }

  // === 私有工具方法 ===

  /**
   * 获取或创建请求日志记录
   */
  private async getOrCreateRequestLog(requestId: string): Promise<CopilotRequestLog> {
    // 先从缓存中获取
    let requestLog = this.activeRequests.get(requestId);
    
    if (!requestLog) {
      // 从数据库中查找
      requestLog = await this.requestLogRepository.findOne({ 
        where: { requestId } 
      });
      
      if (!requestLog) {
        // 创建新记录
        requestLog = new CopilotRequestLog();
        requestLog.requestId = requestId;
        requestLog.status = RequestStatus.IN_PROGRESS;
        requestLog.currentPhase = RequestPhase.CLIENT_REQUEST;
        requestLog = await this.requestLogRepository.save(requestLog);
      }
      
      this.activeRequests.set(requestId, requestLog);
    }
    
    return requestLog;
  }

  /**
   * 清理敏感头信息
   */
  private sanitizeHeaders(headers?: Record<string, any>): Record<string, any> | null {
    if (!headers) return null;
    
    const sensitiveKeys = ['authorization', 'cookie', 'x-api-key', 'bearer'];
    const sanitized = { ...headers };
    
    for (const key of Object.keys(sanitized)) {
      if (sensitiveKeys.some(sensitive => key.toLowerCase().includes(sensitive))) {
        const value = sanitized[key];
        if (typeof value === 'string' && value.length > 10) {
          sanitized[key] = `${value.substring(0, 10)}...`;
        } else {
          sanitized[key] = '[REDACTED]';
        }
      }
    }
    
    return sanitized;
  }

  /**
   * 清理请求体中的敏感信息
   */
  private sanitizeRequestBody(body?: Record<string, any>): Record<string, any> | null {
    if (!body) return null;
    
    const sanitized = JSON.parse(JSON.stringify(body));
    
    // 移除或脚本化敏感字段
    this.redactSensitiveFields(sanitized);
    
    return sanitized;
  }

  /**
   * 清理响应体中的敏感信息
   */
  private sanitizeResponseBody(body?: Record<string, any>): Record<string, any> | null {
    if (!body) return null;
    
    const sanitized = JSON.parse(JSON.stringify(body));
    
    // 响应中一般不包含敏感信息，但保持一致性
    this.redactSensitiveFields(sanitized);
    
    return sanitized;
  }

  /**
   * 递归脚本化敏感字段
   */
  private redactSensitiveFields(obj: any): void {
    if (!obj || typeof obj !== 'object') return;
    
    const sensitiveKeys = ['password', 'token', 'key', 'secret', 'auth', 'credential'];
    
    for (const [key, value] of Object.entries(obj)) {
      if (sensitiveKeys.some(sensitive => key.toLowerCase().includes(sensitive))) {
        if (typeof value === 'string' && value.length > 10) {
          obj[key] = `${value.substring(0, 10)}...`;
        } else {
          obj[key] = '[REDACTED]';
        }
      } else if (Array.isArray(value)) {
        value.forEach(item => this.redactSensitiveFields(item));
      } else if (typeof value === 'object' && value !== null) {
        this.redactSensitiveFields(value);
      }
    }
  }

  // === 公共查询方法 ===

  /**
   * 获取请求日志列表
   */
  async getRequestLogs(options: {
    page?: number;
    pageSize?: number;
    status?: RequestStatus;
    startTime?: Date;
    endTime?: Date;
    userId?: string;
  } = {}): Promise<{
    data: CopilotRequestLog[];
    total: number;
    page: number;
    pageSize: number;
  }> {
    const {
      page = 1,
      pageSize = 20,
      status,
      startTime,
      endTime,
      userId
    } = options;

    const queryBuilder = this.requestLogRepository.createQueryBuilder('log')
      .leftJoinAndSelect('log.fieldMappings', 'mappings')
      .orderBy('log.createdAt', 'DESC');

    if (status) {
      queryBuilder.andWhere('log.status = :status', { status });
    }

    if (startTime) {
      queryBuilder.andWhere('log.createdAt >= :startTime', { startTime });
    }

    if (endTime) {
      queryBuilder.andWhere('log.createdAt <= :endTime', { endTime });
    }

    if (userId) {
      queryBuilder.andWhere('log.userId = :userId', { userId });
    }

    const [data, total] = await queryBuilder
      .skip((page - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount();

    return {
      data,
      total,
      page,
      pageSize
    };
  }

  /**
   * 获取单个请求的详细信息
   */
  async getRequestLogDetail(requestId: string): Promise<CopilotRequestLog | null> {
    return await this.requestLogRepository.findOne({
      where: { requestId },
      relations: ['fieldMappings']
    });
  }

  /**
   * 获取字段映射变化记录
   */
  async getFieldMappings(requestId: string): Promise<CopilotFieldMapping[]> {
    const requestLog = await this.requestLogRepository.findOne({
      where: { requestId },
      select: ['id']
    });

    if (!requestLog) {
      return [];
    }

    return await this.fieldMappingRepository.find({
      where: { requestLogId: requestLog.id },
      order: { createdAt: 'ASC' }
    });
  }

  /**
   * 获取统计信息
   */
  async getStatistics(timeRange?: { start: Date; end: Date }): Promise<{
    totalRequests: number;
    successRequests: number;
    errorRequests: number;
    averageResponseTime: number;
    totalTokensUsed: number;
    topErrors: Array<{ message: string; count: number }>;
  }> {
    const queryBuilder = this.requestLogRepository.createQueryBuilder('log');

    if (timeRange) {
      queryBuilder.where('log.createdAt BETWEEN :start AND :end', timeRange);
    }

    const totalRequests = await queryBuilder.getCount();
    
    const successRequests = await queryBuilder
      .andWhere('log.status = :status', { status: RequestStatus.SUCCESS })
      .getCount();

    const errorRequests = await queryBuilder
      .andWhere('log.status = :status', { status: RequestStatus.ERROR })
      .getCount();

    const avgResult = await queryBuilder
      .select('AVG(log.totalDuration)', 'average')
      .getRawOne();

    const tokenResult = await queryBuilder
      .select('SUM(log.actualInputTokens + log.actualOutputTokens)', 'total')
      .getRawOne();

    const topErrors = await queryBuilder
      .select('log.errorMessage', 'message')
      .addSelect('COUNT(*)', 'count')
      .where('log.status = :status', { status: RequestStatus.ERROR })
      .andWhere('log.errorMessage IS NOT NULL')
      .groupBy('log.errorMessage')
      .orderBy('count', 'DESC')
      .limit(5)
      .getRawMany();

    return {
      totalRequests,
      successRequests,
      errorRequests,
      averageResponseTime: Math.round(avgResult?.average || 0),
      totalTokensUsed: tokenResult?.total || 0,
      topErrors
    };
  }
}